package com.javabi.boardgame.model.board.grid;

import java.util.ArrayList;
import java.util.List;

import com.javabi.boardgame.model.IPiece;
import com.javabi.boardgame.model.board.IBoard;

/**
 * A grid board, suitable for games such as chess and draughts.
 * @param <P> the piece type.
 */
public class GridBoard<P extends IPiece> implements IBoard<GridLocation, P> {

	private final int yLength;
	private final int xLength;
	private final Object[][] board;

	public GridBoard(int xLength, int yLength) {
		if (xLength < 1) {
			throw new IllegalArgumentException("xLength=" + xLength);
		}
		if (yLength < 1) {
			throw new IllegalArgumentException("yLength=" + yLength);
		}
		this.xLength = xLength;
		this.yLength = yLength;

		// Create board
		this.board = new Object[xLength][yLength];
	}

	@Override
	public List<GridLocation> getLocationList() {
		List<GridLocation> list = new ArrayList<GridLocation>();
		for (int x = 1; x <= xLength; x++) {
			for (int y = 1; y <= yLength; y++) {
				list.add(new GridLocation(x, y));
			}
		}
		return list;
	}

	private void checkLocationExists(GridLocation location) {
		if (location.getX() > xLength) {
			throw new IllegalArgumentException("invalid location: " + location + ", xLength=" + xLength);
		}
		if (location.getY() > yLength) {
			throw new IllegalArgumentException("invalid location: " + location + ", yLength=" + yLength);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public P getPiece(GridLocation location) {
		checkLocationExists(location);
		int x = location.getX() - 1;
		int y = location.getY() - 1;
		
		// Get
		return (P) board[x][y];
	}

	@Override
	public void setPiece(GridLocation location, P piece) {
		if (piece == null) {
			throw new NullPointerException("piece");
		}
		checkLocationExists(location);
		int x = location.getX() - 1;
		int y = location.getY() - 1;

		// Set
		board[x][y] = piece;
	}

	@SuppressWarnings("unchecked")
	@Override
	public P removePiece(GridLocation location) {
		checkLocationExists(location);
		int x = location.getX() - 1;
		int y = location.getY() - 1;

		// Remove
		P removed = (P) board[x][y];
		board[x][y] = null;
		return removed;
	}

}
